package com.wg.dome.handle;

import cn.hutool.core.lang.WeightRandom;
import cn.hutool.core.util.RandomUtil;
import com.wg.common.ioc.WgIoc;
import com.wg.dome.ClientPeer;
import com.wg.dome.ErrorCode;
import com.wg.dome.ErrorHelper;
import com.wg.dome.annotation.Request;
import com.wg.dome.entity.config.InitDataEntity;
import com.wg.dome.entity.config.InitHeroEntity;
import com.wg.dome.entity.config.RecruitHeroEntity;
import com.wg.dome.entity.user.HeroEntity;
import com.wg.dome.entity.user.PlayerEntity;
import com.wg.dome.operation.OperationCode;
import com.wg.dome.operation.RecruitHeroRequest;
import com.wg.dome.operation.RecruitHeroResponse;
import com.wg.dome.repository.*;
import com.wg.game.IdGenerator;
import com.wg.common.net.OperationRequest;
import com.wg.common.net.OperationResponse;
import com.wg.common.net.SendParameters;
import com.wg.common.lang.HashTable;

import java.util.*;

/**
 * 招募英雄
 */
@Request(OperationCode = OperationCode.ZHAO_MU)
public class HandleRecruitHeroRequest extends BaseHandle {

    @Override
    public OperationResponse execute(ClientPeer peer, OperationRequest request, SendParameters sendParameters) {
        RecruitHeroRequest recruitHeroRequest = new RecruitHeroRequest(request);

        if (!recruitHeroRequest.isValid()) {
            return ErrorHelper.getInvalidResponse(recruitHeroRequest);
        }

        if (recruitHeroRequest.getPlayerId() != peer.getPlayerId()) {
            return ErrorHelper.getErrorResponse(request.getOperationCode(),
                    ErrorCode.PLAYERID_MATCH_ERROR, recruitHeroRequest.getPlayerId(), peer.getPlayerId());
        }

        PlayerRepository playerRepository = new PlayerRepository();
        PlayerEntity playerEntity = playerRepository.get(recruitHeroRequest.getPlayerId());

        InitDataRepository initDataRepository = new InitDataRepository();
        InitDataEntity initDataEntity = initDataRepository.get();

        ArrayList<Integer> recruitList = new ArrayList<>();
        boolean flag;
        int freeRecruitTime = -1;

        switch (recruitHeroRequest.getType()) {
            case 1:
                long nowTimestamp = System.currentTimeMillis() / 1000;
                if (playerEntity.getRecruitTime() == 0 || (nowTimestamp - playerEntity.getRecruitTime() >= initDataEntity.getFreeRecruitIntervalTime())) {
                    Data data = recruit(1, playerEntity.getSurplus());
                    recruitList = data.getList();
                    flag = data.isFlag();
                    freeRecruitTime = initDataEntity.getFreeRecruitIntervalTime();
                    playerEntity.setRecruitTime(nowTimestamp);
                } else if (playerEntity.getRmb() < initDataEntity.getRecruitRmbOnce()) {
                    return ErrorHelper.getErrorResponse(request.getOperationCode(),
                            ErrorCode.RMB_LIMIT);
                } else {
                    Data data = recruit(1, playerEntity.getSurplus());
                    recruitList = data.getList();
                    flag = data.isFlag();
                    playerEntity.setRmb(playerEntity.getRmb() - initDataEntity.getRecruitRmbOnce());
                }

                if (flag) {
                    playerEntity.setSurplus(10);
                } else {
                    playerEntity.setSurplus(playerEntity.getSurplus() - 1);
                }
                break;

            case 2:
                if (playerEntity.getRmb() < initDataEntity.getRecruitRmbTen()) {
                    return ErrorHelper.getErrorResponse(request.getOperationCode(),
                            ErrorCode.RMB_LIMIT);
                }
                recruitList = recruit(10, 0).getList();
                playerEntity.setRmb(playerEntity.getRmb() - initDataEntity.getRecruitRmbTen());
                break;
            default:
                break;
        }

        playerRepository.update(playerEntity);

        IdGenerator idGenerator = WgIoc.get(IdGenerator.class);
        HashTable[] hashTables = new HashTable[recruitList.size()];
        HeroRepository heroRepository = new HeroRepository();
        int index = 0;
        for (int heroId : recruitList) {
            HeroEntity heroEntity = new HeroEntity();
            heroEntity.setPlayerId(recruitHeroRequest.getPlayerId());
            heroEntity.setId(idGenerator.nextId());
            heroEntity.setsId(heroId);
            heroEntity.setDjLv((short) 1);
            heroEntity.setFsLv((short) 0);
            heroEntity.setJjLv((short) 0);
            heroEntity.setStarLv((short) 0);
            heroRepository.add(heroEntity);

            hashTables[index++] = heroEntity.toHashTable();
        }


        RecruitHeroResponse response = new RecruitHeroResponse();
        response.setRmb(playerEntity.getRmb());
        response.setHeros(hashTables);
        response.setSurplus(playerEntity.getSurplus());
        response.setFreeRecruitTime(freeRecruitTime);
        return new OperationResponse(request.getOperationCode(), response);
    }

    private Data recruit(int count, int surplus) {
        List<WeightRandom.WeightObj<Integer>> weightList = new ArrayList<>();
        List<WeightRandom.WeightObj<Integer>> goodweightList = new ArrayList<>();
        InitRecruitHeroRepository initRecruitHeroRepository = new InitRecruitHeroRepository();
        List<RecruitHeroEntity> entityList = initRecruitHeroRepository.getAll();

        InitHeroRepository initHeroRepository = new InitHeroRepository();
        WeightRandom.WeightObj<Integer> weightObj;
        ArrayList<Integer> goodHeroIdList = new ArrayList<>();

        for (RecruitHeroEntity entity : entityList) {
            weightObj = new WeightRandom.WeightObj<>(entity.getId(), entity.getProbability());
            weightList.add(weightObj);

            InitHeroEntity initHeroEntity = initHeroRepository.get(entity.getId());
            if (initHeroEntity.getQuality() >= 3) {
                goodHeroIdList.add(entity.getId());
                weightObj = new WeightRandom.WeightObj<>(entity.getId(), entity.getProbability());
                goodweightList.add(weightObj);
            }
        }

        WeightRandom<Integer> wr = RandomUtil.weightRandom(weightList);
        ArrayList<Integer> recruitList = new ArrayList<>(count);

        for (int i = 0; i < count; i++) {
            recruitList.add(wr.next());
        }

        boolean flag = false;
        if (count == 1) {
            if (surplus == 1) {
                if (!goodHeroIdList.contains(recruitList.get(0))) {
                    WeightRandom<Integer> weightRandom = RandomUtil.weightRandom(goodweightList);
                    recruitList.remove(0);
                    recruitList.add(0, weightRandom.next());
                }
            }

            if (goodHeroIdList.contains(recruitList.get(0))) {
                flag = true;
            }

        }

        boolean haveGood = false;
        if (count == 10) {
            for (int id : recruitList) {
                if (goodHeroIdList.contains(id)) {
                    haveGood = true;
                }
            }
            if (!haveGood) {
                WeightRandom<Integer> weightRandom = RandomUtil.weightRandom(goodweightList);
                recruitList.remove(0);
                recruitList.add(0, weightRandom.next());
            }
        }

        Data data = new Data();
        data.setList(recruitList);
        data.setFlag(flag);
        return data;
    }

    private static class Data {
        private ArrayList<Integer> list;
        private boolean flag;

        public Data() {
            list = new ArrayList<>();
        }

        public ArrayList<Integer> getList() {
            return list;
        }

        public void setList(ArrayList<Integer> list) {
            this.list = list;
        }

        public boolean isFlag() {
            return flag;
        }

        public void setFlag(boolean flag) {
            this.flag = flag;
        }
    }
}
